/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.cef.designtime.api.increment.property.json;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.inspur.edp.cef.designtime.api.increment.property.AssoColPropIncrement;
import com.inspur.edp.cef.designtime.api.increment.property.BooleanPropertyIncrement;
import com.inspur.edp.cef.designtime.api.increment.property.DatePropertyIncrement;
import com.inspur.edp.cef.designtime.api.increment.property.IncrementPropType;
import com.inspur.edp.cef.designtime.api.increment.property.IntPropertyIncrement;
import com.inspur.edp.cef.designtime.api.increment.property.NativePropertyIncrement;
import com.inspur.edp.cef.designtime.api.increment.property.ObjectPropertyIncrement;
import com.inspur.edp.cef.designtime.api.increment.property.PropertyIncrement;
import com.inspur.edp.cef.designtime.api.increment.property.StringPropertyIncrement;
import com.inspur.edp.cef.designtime.api.json.CefNames;
import com.inspur.edp.cef.designtime.api.json.element.AssoCollectionDeserializer;
import com.inspur.edp.cef.designtime.api.json.element.CefFieldDeserializer;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;

public class PropertyIncrementDeserializer extends JsonDeserializer<PropertyIncrement> {

    @Override
    public PropertyIncrement deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException, JsonProcessingException {

        ObjectMapper mapper = new ObjectMapper();
        JsonNode node = mapper.readTree(jsonParser);
        boolean hasIncrement = node.get(CefNames.HasIncrement).booleanValue();
        return readNativeInfo(node, hasIncrement);

    }

    private NativePropertyIncrement readNativeInfo(JsonNode node, boolean hasIncrement) {
        JsonNode nodePropertyType = node.get(CefNames.PropertyType);
        if (nodePropertyType == null)
            return null;
        NativePropertyIncrement increment = null;
        IncrementPropType type = IncrementPropType.valueOf(nodePropertyType.textValue());
        JsonNode nodeValue = node.get(CefNames.PropertyValue);
        switch (type) {
            case String:
                increment = new StringPropertyIncrement(hasIncrement);
                if (nodeValue != null)
                    increment.setPropertyValue(nodeValue.textValue());
                break;
            case Date:
                increment = new DatePropertyIncrement(hasIncrement);
                if (nodeValue != null) {
                    String txtDate = nodeValue.textValue();
                    increment.setPropertyValue(new Date(txtDate));
                }
                break;
            case Int:
                increment = new IntPropertyIncrement(hasIncrement);
                if (nodeValue != null)
                    increment.setPropertyValue(nodeValue.intValue());
                break;
//            case Decimal:
//                increment = new decimalPr
            case Boolean:
                increment = new BooleanPropertyIncrement(hasIncrement);
                if (nodeValue != null)
                    increment.setPropertyValue(nodeValue.booleanValue());
                break;
            case Object:
                increment = readObjectIncrement(node, nodeValue, hasIncrement);
                break;

        }

        return increment;
    }

    private ObjectPropertyIncrement readObjectIncrement(JsonNode node, JsonNode valueNode, boolean hasIncrement) {
        JsonNode nodeClassName = node.get(CefNames.ObjectIncrementType);
        if (nodeClassName == null)
            return null;
        Class objectClass = null;
        ObjectPropertyIncrement increment = null;
        try {
            objectClass = Class.forName(nodeClassName.textValue());
            Constructor cons = objectClass.getConstructor(boolean.class);
            increment = (ObjectPropertyIncrement) cons.newInstance(hasIncrement);
        } catch (NoSuchMethodException | ClassNotFoundException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(nodeClassName.textValue() + "实例化失败", e);
        }
        if (valueNode == null)
            increment.setPropertyValue(null);

        JsonDeserializer deserializer = increment.getJsonDeserializer();
        if(increment instanceof AssoColPropIncrement)
            ((AssoCollectionDeserializer)deserializer).setCefFieldDeserializer(cefFieldDeserializer);
        ObjectMapper mapper = new ObjectMapper();
        if(deserializer != null ){
            SimpleModule module = new SimpleModule();
            module.addDeserializer(increment.getPropertyIncrementClass(), deserializer);
            mapper.registerModule(module);
        }
        try {
                increment.setPropertyValue(mapper.readValue(mapper.writeValueAsString(valueNode),increment.getPropertyIncrementClass()));
        } catch (JsonProcessingException e) {
            throw new RuntimeException("ObjectValue反序列化失败，类名为" + objectClass.getName(), e);
        } catch (IOException e) {
            throw new RuntimeException("ObjectValue反序列化失败，类名为" + objectClass.getName(), e);
        }

        return increment;
    }






    public CefFieldDeserializer getCefFieldDeserializer() {
        return cefFieldDeserializer;
    }

    public void setCefFieldDeserializer(CefFieldDeserializer cefFieldDeserializer) {
        this.cefFieldDeserializer = cefFieldDeserializer;
    }

    private CefFieldDeserializer cefFieldDeserializer;

}
